﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Threading;
using System.Diagnostics;

namespace BackUpAnyWhere
{
    public partial class BackUpForm : Form
    {
        // ____________________________________________________________________________________________________

        public enum ErrorReason
        {
            NoProblem           = 0,        // 
            ReadOnly            = 1,        //
            NoSpace             = 2,        //
            NoEnoughSpace       = 3,        //
            UnAvailableNet      = 4,        // Mapping of a network drive  
            HasntCheckYet       = 5         // Drive hasn't been check yet 
        }

        // a flag to notify the main form the copy action has finish
        public static bool CloseForm = false;

        // a counter which use to update the value of the status bar
        public static int ProgressCount = 0;

        // array for the file counters
        public static int[] FileCounter = new int[7];

        // a List for the files which are too old and may be deleted
        public static List<string> FileToDeleteList = new List<string>();

        public string newDirName = "";
        public static int currentRunningCase = 0;
        public int driveNum = 0;
        public const int MAX_DRIVE = 28;
        public DriveProperties[] compDriveList = new DriveProperties[MAX_DRIVE];
        public Thread FileCopyThread;

        // ____________________________________________________________________________________________________

        public BackUpForm(int Stat)
        {   
            currentRunningCase = Stat;
            InitializeComponent();
        }

        // ____________________________________________________________________________________________________

        private void BackUpForm_Load(object sender, EventArgs e)
        {
            this.Text = "BackUp AnyWhere© - " + System.Environment.MachineName;

            ProgressBarTimer.Enabled = false;

            CopyProgressBar.Value = 0;
            CopyProgressBar.Visible = false; 
            CopyProgressBar.Maximum = FileHandle.GetFilesRecursive(Path.GetPathRoot(Application.ExecutablePath));
            FileCounter[0] = CopyProgressBar.Maximum;

            if (currentRunningCase == (int)BackUpAnyWhere.Program.UseCase.UC1 || currentRunningCase == (int)BackUpAnyWhere.Program.UseCase.UC1_1)
            {
                StartBackUpButton.Enabled = false;
                changeDirButton.Enabled = true;
                changeDirButton.Text = "Set &Directory";
                StartBackUpButton.Text = "Start &Backup";
                if (currentRunningCase == (int)BackUpAnyWhere.Program.UseCase.UC1)
                    DisplayUserMessage(1,"");
                else
                    DisplayUserMessage(10,"");
            }
            else if (currentRunningCase == (int)BackUpAnyWhere.Program.UseCase.UC2 ||
                     currentRunningCase == (int)BackUpAnyWhere.Program.UseCase.UC3_1 ||
                     currentRunningCase == (int)BackUpAnyWhere.Program.UseCase.UC3_2)
            {
                autoSyncCheckBox.Visible = true;
                autoSyncCheckBox.Checked = IniFileHandle.isAutomated();
                StartBackUpButton.Enabled = true;
                changeDirButton.Enabled = true;
                changeDirButton.Text = "Change &Directory";
                StartBackUpButton.Text = "Start &Synchronize";
                newDirName = IniFileHandle.readKey("Path");
                DisplayUserMessage(4, newDirName);

                if (currentRunningCase == (int)BackUpAnyWhere.Program.UseCase.UC3_1)
                {
                    this.WindowState = FormWindowState.Minimized;
                    StartBackUpButton_Click(new object(), new EventArgs());
                }
            }

            driveNum = GetDriveList();
            DriveComboBox.SelectedIndex = -1;
        }

        private void ChangeDirButton_Click(object sender, EventArgs e)
        {
            StartBackUpButton.Enabled = false;
            StartBackUpButton.Text = "Start &Backup";
            currentRunningCase = (int)BackUpAnyWhere.Program.UseCase.UC1_1;

            CopyProgressBar.Location = new System.Drawing.Point(171, 310);
            DisplayUserMessage(2, "");
            GreyLine.Visible = true;
            WhiteLine.Visible = true;
            DriveComboBox.Visible = true;
            DirectoryTreeView.Visible = true;
            changeDirButton.Enabled = false;
            ClientSize = new System.Drawing.Size(373, 326);

            DriveComboBox.Items.Clear();
            for (int itemIndex = 0; itemIndex < driveNum; itemIndex++)
                DriveComboBox.Items.Add(compDriveList[itemIndex]._comboItem);
        }

        private void StopThreads()
        {
            if (FileCopyThread != null)
                FileCopyThread.Abort();
        }

        private int GetDriveList()
        {
            DriveInfo[] driveTempList = DriveInfo.GetDrives();

            foreach (DriveInfo drive in driveTempList)
            {
                if ((String.Compare(drive.Name.ToString(), Path.GetPathRoot(Application.ExecutablePath)) != 0))
                {
                    compDriveList[driveNum] = new DriveProperties();
                    compDriveList[driveNum]._driveName = drive.Name;
                    compDriveList[driveNum]._rootDirectory = drive.RootDirectory;
                    compDriveList[driveNum]._drive = drive;
                    compDriveList[driveNum]._reason = (int)ErrorReason.HasntCheckYet;
                    compDriveList[driveNum]._driveReady = false;
                    compDriveList[driveNum]._comboItem = new ComboItem(drive.Name.ToString(), Color.LightGray);
                    compDriveList[driveNum]._thread = new Thread(new ParameterizedThreadStart(UpdateDriveAvailability));
                    DriveComboBox.Items.Add(compDriveList[driveNum]._comboItem);
                    
                    // http://msdn.microsoft.com/en-US/library/6x4c42hc%28v=VS.80%29.aspx
                    compDriveList[driveNum]._thread.Start(driveNum);
                    compDriveList[driveNum]._thread.Name = drive.Name.ToString();
                    driveNum++;
                }
            }
            return (driveNum);
        }

        private void UpdateDriveAvailability(object driveNum)
        {
            long MyDriveSize = FileHandle.GetDriveUseSize(new DriveInfo(Path.GetPathRoot(Application.ExecutablePath)));

            if (compDriveList[(int)driveNum]._drive.IsReady)
            {
                if ((compDriveList[(int)driveNum]._drive.AvailableFreeSpace > 0) &&
                    (MyDriveSize < compDriveList[(int)driveNum]._drive.AvailableFreeSpace))
                {
                    compDriveList[(int)driveNum]._driveReady = true;
                    compDriveList[(int)driveNum]._comboItem._color = Color.Black;
                    compDriveList[(int)driveNum]._reason = (int)ErrorReason.NoProblem;
                }
                else if (MyDriveSize > compDriveList[(int)driveNum]._drive.AvailableFreeSpace)
                {
                    compDriveList[(int)driveNum]._driveReady = false;
                    compDriveList[(int)driveNum]._comboItem._color = Color.Red;
                    compDriveList[(int)driveNum]._reason = (int)ErrorReason.NoEnoughSpace;
                }
                else 
                {
                    compDriveList[(int)driveNum]._driveReady = false;
                    compDriveList[(int)driveNum]._comboItem._color = Color.Red;
                    compDriveList[(int)driveNum]._reason = (int)ErrorReason.ReadOnly;
                }
            }
            else
                compDriveList[(int)driveNum]._reason = (int)ErrorReason.UnAvailableNet;
        }

        private void FilesRecursive(object driveName)
        {
            FileHandle.GetFilesRecursive(driveName.ToString());
        }

        private void DriveComboBox_OnDisplayMemberChanged(object sender, EventArgs e)
        {
            DirectoryTreeView.Visible = true;
            DirectoryTreeView.Name = "Main";

            /*
             * if the new drive is the same as what currently in the DirectoryTreeView,
             * there is no need to redrew the TreeView. 
             * first checking whether the new drive is not empty (-1). then checking 
             * whether the TreeView is empty (Nodes.Count == 0). if so then we should go ahead
             * if not, means the tree is not empty, then check if it's the same drive or not
             */

            if ((DriveComboBox.SelectedIndex > -1) && 
                ((DirectoryTreeView.Nodes.Count == 0) || 
                ((DirectoryTreeView.Nodes.Count > 0) && (compDriveList[DriveComboBox.SelectedIndex]._driveName != DirectoryTreeView.Nodes[0].Text))))
            {
                switch (compDriveList[DriveComboBox.SelectedIndex]._reason)
                {
                    case (int)ErrorReason.NoProblem:
                        DirectoryTreeView.Nodes.Clear();
                        String path = compDriveList[DriveComboBox.SelectedIndex]._rootDirectory.Name.ToString();
                        DirectoryTreeView.Nodes.Add(path);
                        if (FolderTreeView.HasSubFolders(path))
                            DirectoryTreeView.Nodes[0].Nodes.Add("");
                        break;
                    case (int)ErrorReason.NoSpace:
                        DirectoryTreeView.Nodes.Clear();
                        DirectoryTreeView.Nodes.Add("Drive " + compDriveList[DriveComboBox.SelectedIndex]._driveName + " has no available space for the backup\n");
                        break;
                    case (int)ErrorReason.ReadOnly:
                        DirectoryTreeView.Nodes.Clear();
                        DirectoryTreeView.Nodes.Add("Drive " + compDriveList[DriveComboBox.SelectedIndex]._driveName + " is READ ONLY drive and cannot be use for the backup");
                        break;
                    case (int)ErrorReason.NoEnoughSpace:
                        DirectoryTreeView.Nodes.Clear();
                        DirectoryTreeView.Nodes.Add("Drive " + compDriveList[DriveComboBox.SelectedIndex]._driveName + " has no enough space for the backup\n");
                        break;
                    case (int)ErrorReason.UnAvailableNet:
                        DirectoryTreeView.Nodes.Clear();
                        DirectoryTreeView.Nodes.Add("Drive " + compDriveList[DriveComboBox.SelectedIndex]._driveName + " is not available this time\n");
                        break;
                    case (int)ErrorReason.HasntCheckYet:
                        DirectoryTreeView.Nodes.Clear();
                        DirectoryTreeView.Nodes.Add("Drive " + compDriveList[DriveComboBox.SelectedIndex]._driveName + " is still under verification\n");
                        break;
                    default:
                        break;
                }

                    DisplayUserMessage(2, "");
                    StartBackUpButton.Enabled = false;
                    createDirButton.Enabled = false;
            }
        }

        private void DriveComboBox_DrawItem(object sender, System.Windows.Forms.DrawItemEventArgs e)
        {
            if (e.Index >= 0)
            {
                ComboItem item = DriveComboBox.Items[e.Index] as ComboItem;
                SolidBrush b = (SolidBrush)new SolidBrush(item._color);
                e.Graphics.DrawString(item._str, DriveComboBox.Font, b, e.Bounds);
                e.DrawFocusRectangle();
            } 
        }
        
        private void DirectoryTreeView_AfterSelect(object sender, TreeViewEventArgs e)
        {
            if (compDriveList[DriveComboBox.SelectedIndex]._driveReady)
            {
                createDirButton.Enabled = true;
                createDirButton.Visible = true;
                autoSyncCheckBox.Visible = true;
                StartBackUpButton.Enabled = true;
                newDirName = e.Node.FullPath;
                DisplayUserMessage(3, newDirName);

                if (string.Compare(newDirName, IniFileHandle.readKey("Path")) == 0)
                {
                    StartBackUpButton.Text = "Start &Synchronize";
                    currentRunningCase = (int)BackUpAnyWhere.Program.UseCase.UC2;
                }
                else
                {
                    StartBackUpButton.Text = "Start &Backup";
                    currentRunningCase = (int)BackUpAnyWhere.Program.UseCase.UC1_1;
                }
            }
        }

        private void DisplayError(String ErrorMesage)
        {
            /*
             * MessageBox.Show(messageBoxText, 
             *                 caption, 
             *                 button, 
             *                 icon, 
             *                 defaultResult, 
             *                 options);
             */

            switch (ErrorMesage)
            {
                case "PathNotAvailable":
                    MessageBox.Show("The Path which is configured in the ini file is not Available\nPlease select a new ",
                                    "Error Message",
                                     MessageBoxButtons.OK,
                                     MessageBoxIcon.Exclamation);
                    break;
                case "InvalidDirectoryName":
                    MessageBox.Show("The new directory name invalid\nPlease type a new one",
                                     "Error Message",
                                     MessageBoxButtons.OK,
                                     MessageBoxIcon.Exclamation);
                    break;
                default:
                    break;
            }
        }

        private void DisplayUserMessage(int messageID, string DirName)
        {
            switch (messageID)
            {
                case 1:
                    DebugMessage("\nUseCase 1\n");
                    userMessageLabel.Text = "Hello\n\n";
                    userMessageLabel.Text = userMessageLabel.Text + "This program will automatically backup your\n";
                    userMessageLabel.Text = userMessageLabel.Text + "personal files, located on your flash drive.\n\n";
                    userMessageLabel.Text = userMessageLabel.Text + "Please select the destination of the backup.";
                    break;
                case 2:
                    userMessageLabel.Text = "Hello\n\n";
                    userMessageLabel.Text = userMessageLabel.Text + "Please use the drop down menu to select the\n";
                    userMessageLabel.Text = userMessageLabel.Text + "drive and the path for the backup destination.";
                    break;
                case 3:
                    userMessageLabel.Text = "Hello\n\n";
                    userMessageLabel.Text = userMessageLabel.Text + "You have choose to backup your data to\n";
                    userMessageLabel.Text = userMessageLabel.Text + "   " + DirName + "\n\n";
                    userMessageLabel.Text = userMessageLabel.Text + "Please select StartBackUp to continue\n";
                    break;
                case 4:
                    DebugMessage("\nUseCase 2\n");
                    userMessageLabel.Text = "Welcome Back\n\n";
                    userMessageLabel.Text = userMessageLabel.Text + "Your last backup is located at\n";
                    userMessageLabel.Text = userMessageLabel.Text + "   " + DirName + "\n\n";
                    userMessageLabel.Text = userMessageLabel.Text + "Please select StartBackUp or Change Directory\n";
                    break;
                case 10:
                    DebugMessage("\nUseCase 1_1\n");
                    userMessageLabel.Text = "Welcome Back\n\n";
                    userMessageLabel.Text = userMessageLabel.Text + "Unfortunately, the path which has been use\n";
                    userMessageLabel.Text = userMessageLabel.Text + "for the previous backup is unalienable.\n\n";
                    userMessageLabel.Text = userMessageLabel.Text + "Please select the destination of the backup.";
                    break;

                default:
                    DebugMessage("\nDefault case\n");
                    break;
            }
        }

        private void DebugMessage(String messageToDisplay)
        {
            Console.WriteLine(messageToDisplay);
        }

        private void createDirButton_Click(object sender, EventArgs e)
        {
            if (DisplayDirectoryForm("New Directory name", "Please specify the directory name:", ref newDirName) == DialogResult.OK)
            {
                if (FileHandle.ValidateDirectoryName(newDirName))
                {
                    TreeNode SelectedNode = DirectoryTreeView.SelectedNode;
                    SelectedNode.Nodes.Add(newDirName);
                    newDirName = DirectoryTreeView.SelectedNode.FullPath.ToString() + "\\" + newDirName;
                    FileHandle.CreateDirectory(newDirName);
               }
                else
                    DisplayError("InvalidDirectoryName");
            }
        }

        public static DialogResult DisplayDirectoryForm(string formTitle, string labelText, ref string value)
        {
            Form form = new Form();
            TextBox textBox = new TextBox();
            Button buttonOk = new Button();
            Button buttonCancel = new Button();

            Label label = new Label();
            label.Text = labelText;
            label.SetBounds(10, 14, 200, 20);
            label.AutoSize = true;

            buttonOk.Text = "OK";
            buttonCancel.Text = "Cancel";
            buttonOk.DialogResult = DialogResult.OK;
            buttonCancel.DialogResult = DialogResult.Cancel;

            textBox.SetBounds(10, 34, 200, 20);
            buttonOk.SetBounds(220, 34, 53, 20);
            buttonCancel.SetBounds(280, 34, 53, 20);

            textBox.Anchor = textBox.Anchor | AnchorStyles.Right;
            buttonOk.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
            buttonCancel.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;

            form.Text = formTitle;
            form.ClientSize = new Size(340, 70);
            form.Controls.AddRange(new Control[] { label,textBox, buttonOk, buttonCancel });
            form.FormBorderStyle = FormBorderStyle.FixedDialog;
            form.StartPosition = FormStartPosition.CenterParent;
            form.MinimizeBox = false;
            form.MaximizeBox = false;
            form.AcceptButton = buttonOk;
            form.CancelButton = buttonCancel;

            DialogResult dialogResult = form.ShowDialog();
            value = textBox.Text;
            return dialogResult;
        }

        private void StartBackUpButton_Click(object sender, EventArgs e)
        {
            StartBackUpButton.Enabled = false;
            changeDirButton.Enabled = false;
            createDirButton.Enabled = false;
            CopyProgressBar.Visible = true;
            ProgressBarTimer.Start();
            ProgressBarTimer.Enabled = true;

            // Save the path of the backup into the Inifile
            IniFileHandle.addKey("Path", newDirName);

            FileCopyThread = new Thread(StartFileCopy);
            FileCopyThread.Name = "StartFileCopy";
            FileCopyThread.Start();
        }

        public void StartFileCopy()
        {
            StatusBarFirstLabel.Text = "Copying files to destination - " + CopyProgressBar.Value / CopyProgressBar.Maximum;
            string path = Path.GetPathRoot(Application.ExecutablePath);
            FileHandle CopyFileObj = new FileHandle(path, newDirName + "\\");
            CopyFileObj.FileCopyAndSync();
            FileToDeleteList = CopyFileObj.Chack_syc();
            FileCounter[(int)BackUpAnyWhere.Program.FileCounterType.FileExist] = CopyFileObj.getFileCounter((int)BackUpAnyWhere.Program.FileCounterType.FileExist); 
            FileCounter[(int)BackUpAnyWhere.Program.FileCounterType.FileCopy] = CopyFileObj.getFileCounter((int)BackUpAnyWhere.Program.FileCounterType.FileCopy);
            FileCounter[(int)BackUpAnyWhere.Program.FileCounterType.FileNotCopeid] = CopyFileObj.getFileCounter((int)BackUpAnyWhere.Program.FileCounterType.FileNotCopeid);
            FileCounter[(int)BackUpAnyWhere.Program.FileCounterType.FileCouldNotCopeid] = CopyFileObj.getFileCounter((int)BackUpAnyWhere.Program.FileCounterType.FileCouldNotCopeid);
            FileCounter[(int)BackUpAnyWhere.Program.FileCounterType.FileSync] = CopyFileObj.getFileCounter((int)BackUpAnyWhere.Program.FileCounterType.FileSync);
            FileCounter[(int)BackUpAnyWhere.Program.FileCounterType.FileToDelete] = CopyFileObj.getFileCounter((int)BackUpAnyWhere.Program.FileCounterType.FileToDelete);
            CloseForm = true;
        }

        public static void NotificationUpdate(int Notification)
        {
            if (Notification == (int)BackUpAnyWhere.Program.NotificationType.FileUpdate)
                ProgressCount++;
            else if (Notification == (int)BackUpAnyWhere.Program.NotificationType.FormClose)
                CloseForm = true;
        }

        private void ProgressBarTimer_Tick(object sender, EventArgs e)
        {
            if (!CloseForm)
            {
                CopyProgressBar.Value = ProgressCount;
                StatusBarFirstLabel.Text = StatusBarFirstLabel.Text = "Copying files to destination - " + (100 * CopyProgressBar.Value / CopyProgressBar.Maximum).ToString() + "%";
            }
            else
                this.Close();
        }

        private void autoSyncCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            Console.WriteLine(autoSyncCheckBox.Checked.ToString());
            IniFileHandle.addKey("Automation", autoSyncCheckBox.Checked.ToString());
        }
    }
}


